using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Linq;
using Matrix.Configuration.Contracts;
using Matrix.Configuration;
using Matrix.Configuration.DTOs;
using Matrix.Configuration.Events;

namespace Matrix.Configuration.Application.Services
{
    /// <summary>
    /// 配置命令服务
    /// 专门负责所有写操作，包括创建、更新、删除和批量操作
    /// </summary>
    public class ConfigurationCommandService : ApplicationService, IConfigurationCommandService
    {
        private readonly IRepository<ConfigurationItem, Guid> _configurationRepository;
        private readonly IDistributedEventBus _distributedEventBus;
        private readonly ILogger<ConfigurationCommandService> _logger;

        public ConfigurationCommandService(
            IRepository<ConfigurationItem, Guid> configurationRepository,
            IDistributedEventBus distributedEventBus,
            ILogger<ConfigurationCommandService> logger)
        {
            _configurationRepository = configurationRepository;
            _distributedEventBus = distributedEventBus;
            _logger = logger;
        }

        /// <summary>
        /// 创建配置项
        /// </summary>
        public async Task<ConfigurationItemDto> CreateAsync(CreateConfigurationItemDto input)
        {
            _logger.LogInformation("开始创建配置项: {Key} - {Namespace}", input.Key, input.Namespace);

            try
            {
                // 检查是否已存在相同配置
                var existingItem = await FindExistingItemAsync(input.Key, input.Namespace);
                if (existingItem != null)
                {
                    throw new Volo.Abp.BusinessException("ConfigurationItemAlreadyExists",
                        $"配置项已存在: {input.Key} 在命名空间 {input.Namespace}");
                }

                // 创建新的配置项
                var configurationItem = new ConfigurationItem(
                    GuidGenerator.Create(),
                    input.Namespace,
                    input.Key,
                    input.Value,
                    input.DataType ?? ConfigurationItemConsts.DefaultDataType,
                    input.Category,
                    input.Description
                );

                await _configurationRepository.InsertAsync(configurationItem);

                // 发布配置创建事件
                await PublishConfigurationChangedEventAsync(new ConfigurationChangedEto
                {
                    EventId = Guid.NewGuid(),
                    Key = input.Key,
                    Namespace = input.Namespace,
                    OldValue = null,
                    NewValue = input.Value,
                    Category = input.Category,
                    ValueType = input.DataType ?? ConfigurationItemConsts.DefaultDataType,
                    EventTime = Clock.Now,
                    ChangeSource = ConfigurationChangeSource.ApiCall,
                    ChangeInfo = new ConfigurationChangeInfo
                    {
                        ChangedBy = CurrentUser.Name ?? CurrentUser.Id?.ToString() ?? "System",
                        ChangedByName = CurrentUser.Name ?? "System"
                    }
                });

                _logger.LogInformation("配置项创建成功: {Id} - {Key}", configurationItem.Id, input.Key);

                return ObjectMapper.Map<ConfigurationItem, ConfigurationItemDto>(configurationItem);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "创建配置项失败: {Key} - {Namespace}", input.Key, input.Namespace);
                throw;
            }
        }

        /// <summary>
        /// 更新配置项
        /// </summary>
        public async Task<ConfigurationItemDto> UpdateAsync(Guid id, UpdateConfigurationItemDto input)
        {
            _logger.LogInformation("开始更新配置项: {Id}", id);

            try
            {
                var configurationItem = await _configurationRepository.GetAsync(id);
                var oldValue = configurationItem.Value;
                var oldCategory = configurationItem.Category;

                _logger.LogInformation("更新前 - Value: {Value}, Category: {Category}", configurationItem.Value, configurationItem.Category);

                // 更新属性
                if (!string.IsNullOrEmpty(input.Value))
                {
                    _logger.LogInformation("正在更新Value: {Value}, DataType: {DataType}", input.Value, input.DataType);
                    configurationItem.SetValue(input.Value, input.DataType);
                }

                if (!string.IsNullOrEmpty(input.Category))
                {
                    _logger.LogInformation("正在更新Category: {Category}", input.Category);
                    configurationItem.SetCategory(input.Category);
                }

                if (!string.IsNullOrEmpty(input.Description))
                {
                    _logger.LogInformation("正在更新Description: {Description}", input.Description);
                    configurationItem.SetDescription(input.Description);
                }

                if (!string.IsNullOrEmpty(input.DataType))
                {
                    _logger.LogInformation("正在更新DataType: {DataType}", input.DataType);
                    configurationItem.SetDataType(input.DataType);
                }

                _logger.LogInformation("调用UpdateAsync前 - Value: {Value}, Category: {Category}", configurationItem.Value, configurationItem.Category);

                await _configurationRepository.UpdateAsync(configurationItem);

                _logger.LogInformation("更新后 - Value: {Value}, Category: {Category}", configurationItem.Value, configurationItem.Category);

                // 映射为DTO前的最终检查
                _logger.LogInformation("映射为DTO前 - Entity Value: {Value}, Entity Category: {Category}", configurationItem.Value, configurationItem.Category);

                var resultDto = ObjectMapper.Map<ConfigurationItem, ConfigurationItemDto>(configurationItem);

                _logger.LogInformation("映射为DTO后 - DTO Value: {Value}, DTO Category: {Category}", resultDto.Value, resultDto.Category);

                // 发布配置更新事件
                if (oldValue != configurationItem.Value)
                {
                    await PublishConfigurationChangedEventAsync(new ConfigurationChangedEto
                    {
                        EventId = Guid.NewGuid(),
                        Key = configurationItem.Key,
                        Namespace = configurationItem.Namespace,
                        OldValue = oldValue,
                        NewValue = configurationItem.Value,
                        Category = configurationItem.Category,
                        ValueType = configurationItem.DataType,
                        EventTime = Clock.Now,
                        ChangeSource = ConfigurationChangeSource.ApiCall,
                        ChangeInfo = new ConfigurationChangeInfo
                        {
                            ChangedBy = CurrentUser.Name ?? CurrentUser.Id?.ToString() ?? "System",
                            ChangedByName = CurrentUser.Name ?? "System"
                        }
                    });
                }

                _logger.LogInformation("配置项更新成功: {Id} - {Key}", id, configurationItem.Key);

                return resultDto;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "更新配置项失败: {Id}", id);
                throw;
            }
        }

        /// <summary>
        /// 删除配置项
        /// </summary>
        public async Task DeleteAsync(Guid id)
        {
            _logger.LogInformation("开始删除配置项: {Id}", id);

            try
            {
                var configurationItem = await _configurationRepository.GetAsync(id);

                // 发布配置删除事件
                await PublishConfigurationChangedEventAsync(new ConfigurationChangedEto
                {
                    EventId = Guid.NewGuid(),
                    Key = configurationItem.Key,
                    Namespace = configurationItem.Namespace,
                    OldValue = configurationItem.Value,
                    NewValue = null,
                    Category = configurationItem.Category,
                    ValueType = configurationItem.DataType,
                    EventTime = Clock.Now,
                    ChangeSource = ConfigurationChangeSource.ApiCall,
                    ChangeInfo = new ConfigurationChangeInfo
                    {
                        ChangedBy = CurrentUser.Name ?? CurrentUser.Id?.ToString() ?? "System",
                        ChangedByName = CurrentUser.Name ?? "System"
                    }
                });

                await _configurationRepository.DeleteAsync(id);

                _logger.LogInformation("配置项删除成功: {Id} - {Key}", id, configurationItem.Key);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "删除配置项失败: {Id}", id);
                throw;
            }
        }

        /// <summary>
        /// 通过键名删除配置
        /// </summary>
        public async Task DeleteByKeyAsync(GetConfigurationItemInput input)
        {
            _logger.LogInformation("开始通过键名删除配置: {Key} - {Namespace}", input.Key, input.Namespace);

            try
            {
                var configurationItem = await FindExistingItemAsync(input.Key, input.Namespace);
                if (configurationItem == null)
                {
                    _logger.LogWarning("要删除的配置项不存在: {Key} - {Namespace}", input.Key, input.Namespace);
                    return;
                }

                // 发布配置删除事件
                await PublishConfigurationChangedEventAsync(new ConfigurationChangedEto
                {
                    EventId = Guid.NewGuid(),
                    Key = input.Key,
                    Namespace = input.Namespace,
                    OldValue = configurationItem.Value,
                    NewValue = null,
                    Category = configurationItem.Category,
                    ValueType = configurationItem.DataType,
                    EventTime = Clock.Now,
                    ChangeSource = ConfigurationChangeSource.ApiCall,
                    ChangeInfo = new ConfigurationChangeInfo
                    {
                        ChangedBy = CurrentUser.Name ?? CurrentUser.Id?.ToString() ?? "System",
                        ChangedByName = CurrentUser.Name ?? "System"
                    }
                });

                await _configurationRepository.DeleteAsync(configurationItem.Id);

                _logger.LogInformation("通过键名删除配置成功: {Key} - {Namespace}", input.Key, input.Namespace);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "通过键名删除配置失败: {Key} - {Namespace}", input.Key, input.Namespace);
                throw;
            }
        }

        /// <summary>
        /// 设置类型化配置值
        /// </summary>
        public async Task SetTypedAsync<T>(GetConfigurationItemInput input, T value)
        {
            _logger.LogInformation("开始设置类型化配置值: {Key} - {Type} - {Namespace}",
                input.Key, typeof(T).Name, input.Namespace);

            try
            {
                var stringValue = ConvertTypedValueToString(value);
                var existingItem = await FindExistingItemAsync(input.Key, input.Namespace);
                var oldValue = existingItem?.Value;

                if (existingItem == null)
                {
                    // 创建新的配置项
                    var configurationItem = new ConfigurationItem(
                        GuidGenerator.Create(),
                        input.Key,
                        stringValue,
                        GetDefaultCategoryFromType(typeof(T)),
                        $"自动创建的 {typeof(T).Name} 类型配置项",
                        input.Namespace,
                        GetDataTypeFromType(typeof(T))
                    );

                    await _configurationRepository.InsertAsync(configurationItem);

                    // 发布配置创建事件
                    await PublishConfigurationChangedEventAsync(new ConfigurationChangedEto
                    {
                        EventId = Guid.NewGuid(),
                        Key = input.Key,
                        Namespace = input.Namespace,
                        OldValue = null,
                        NewValue = stringValue,
                        Category = configurationItem.Category,
                        ValueType = GetDataTypeFromType(typeof(T)),
                        EventTime = Clock.Now,
                        ChangeSource = ConfigurationChangeSource.ApiCall,
                        ChangeInfo = new ConfigurationChangeInfo
                        {
                            ChangedBy = CurrentUser.Name ?? CurrentUser.Id?.ToString() ?? "System",
                            ChangedByName = CurrentUser.Name ?? "System"
                        }
                    });
                }
                else
                {
                    // 更新现有配置项
                    existingItem.SetValue(stringValue, GetDataTypeFromType(typeof(T)));
                    await _configurationRepository.UpdateAsync(existingItem);

                    // 发布配置更新事件
                    await PublishConfigurationChangedEventAsync(new ConfigurationChangedEto
                    {
                        EventId = Guid.NewGuid(),
                        Key = input.Key,
                        Namespace = input.Namespace,
                        OldValue = oldValue,
                        NewValue = stringValue,
                        Category = existingItem.Category,
                        ValueType = GetDataTypeFromType(typeof(T)),
                        EventTime = Clock.Now,
                        ChangeSource = ConfigurationChangeSource.ApiCall,
                        ChangeInfo = new ConfigurationChangeInfo
                        {
                            ChangedBy = CurrentUser.Name ?? CurrentUser.Id?.ToString() ?? "System",
                            ChangedByName = CurrentUser.Name ?? "System"
                        }
                    });
                }

                _logger.LogInformation("设置类型化配置值成功: {Key} - {Type}", input.Key, typeof(T).Name);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "设置类型化配置值失败: {Key} - {Type}", input.Key, typeof(T).Name);
                throw;
            }
        }

        /// <summary>
        /// 批量设置配置
        /// </summary>
        public async Task<ListResultDto<ConfigurationItemDto>> SetBatchAsync(List<BatchConfigurationItemDto> configurations)
        {
            _logger.LogInformation("开始批量设置配置，数量: {Count}", configurations?.Count ?? 0);

            if (configurations == null || configurations.Count == 0)
            {
                return new ListResultDto<ConfigurationItemDto>(new List<ConfigurationItemDto>());
            }

            var results = new List<ConfigurationItemDto>();
            var changeEvents = new List<ConfigurationChangedEto>();

            try
            {
                foreach (var config in configurations)
                {
                    var existingItem = await FindExistingItemAsync(config.Key, config.Namespace);
                    var oldValue = existingItem?.Value;

                    if (existingItem == null)
                    {
                        // 创建新的配置项
                        var configurationItem = new ConfigurationItem(
                            GuidGenerator.Create(),
                            config.Key,
                            config.Value,
                            config.Category,
                            config.Description,
                            config.Namespace,
                            config.DataType ?? ConfigurationItemConsts.DefaultDataType
                        );

                        await _configurationRepository.InsertAsync(configurationItem);
                        results.Add(ObjectMapper.Map<ConfigurationItem, ConfigurationItemDto>(configurationItem));

                        // 记录创建事件
                        changeEvents.Add(new ConfigurationChangedEto
                        {
                            EventId = Guid.NewGuid(),
                            Key = config.Key,
                            Namespace = config.Namespace,
                            OldValue = null,
                            NewValue = config.Value,
                            Category = config.Category,
                            ValueType = config.DataType ?? ConfigurationItemConsts.DefaultDataType,
                            EventTime = Clock.Now,
                            ChangeSource = ConfigurationChangeSource.ApiCall,
                            ChangeInfo = new ConfigurationChangeInfo
                            {
                                ChangedBy = CurrentUser.Name ?? CurrentUser.Id?.ToString() ?? "System",
                                ChangedByName = CurrentUser.Name ?? "System"
                            }
                        });
                    }
                    else
                    {
                        // 更新现有配置项
                        existingItem.SetValue(config.Value, config.DataType ?? ConfigurationItemConsts.DefaultDataType);
                        if (!string.IsNullOrEmpty(config.Category))
                        {
                            existingItem.SetCategory(config.Category);
                        }
                        if (!string.IsNullOrEmpty(config.Description))
                        {
                            existingItem.SetDescription(config.Description);
                        }
                        if (!string.IsNullOrEmpty(config.DataType))
                        {
                            existingItem.SetDataType(config.DataType);
                        }

                        await _configurationRepository.UpdateAsync(existingItem);
                        results.Add(ObjectMapper.Map<ConfigurationItem, ConfigurationItemDto>(existingItem));

                        // 记录更新事件
                        changeEvents.Add(new ConfigurationChangedEto
                        {
                            EventId = Guid.NewGuid(),
                            Key = config.Key,
                            Namespace = config.Namespace,
                            OldValue = oldValue,
                            NewValue = config.Value,
                            Category = existingItem.Category,
                            ValueType = existingItem.DataType,
                            EventTime = Clock.Now,
                            ChangeSource = ConfigurationChangeSource.ApiCall,
                            ChangeInfo = new ConfigurationChangeInfo
                            {
                                ChangedBy = CurrentUser.Name ?? CurrentUser.Id?.ToString() ?? "System",
                                ChangedByName = CurrentUser.Name ?? "System"
                            }
                        });
                    }
                }

                // 批量发布变更事件
                foreach (var @event in changeEvents)
                {
                    await PublishConfigurationChangedEventAsync(@event);
                }

                _logger.LogInformation("批量设置配置完成，成功数量: {Count}", results.Count);
                return new ListResultDto<ConfigurationItemDto>(results);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量设置配置失败");
                throw;
            }
        }

        #region 私有方法

        private async Task<ConfigurationItem?> FindExistingItemAsync(string key, string @namespace)
        {
            var queryable = await _configurationRepository.GetQueryableAsync();
            return await AsyncExecuter.FirstOrDefaultAsync(
                queryable.Where(x => x.Key == key && x.Namespace == @namespace)
            );
        }

        private async Task PublishConfigurationChangedEventAsync(ConfigurationChangedEto eventData)
        {
            try
            {
                await _distributedEventBus.PublishAsync(eventData);
                _logger.LogDebug("配置变更事件发布成功: {Key} - {ChangeType}", eventData.Key, eventData.ChangeType);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "发布配置变更事件失败: {Key} - {ChangeType}", eventData.Key, eventData.ChangeType);
                // 事件发布失败不应该影响主要业务逻辑，只记录日志
            }
        }

        private string ConvertTypedValueToString<T>(T value)
        {
            if (value == null)
            {
                return string.Empty;
            }

            var type = typeof(T);

            // 基础类型直接转换
            if (type == typeof(string))
            {
                return value.ToString()!;
            }
            else if (type == typeof(bool))
            {
                return value.ToString()!.ToLowerInvariant();
            }
            else if (type.IsPrimitive || type == typeof(decimal))
            {
                return value.ToString()!;
            }

            // 复杂类型使用JSON序列化
            return System.Text.Json.JsonSerializer.Serialize(value);
        }

        private string GetDataTypeFromType(Type type)
        {
            if (type == typeof(string)) return "string";
            if (type == typeof(int) || type == typeof(int?)) return "int";
            if (type == typeof(long) || type == typeof(long?)) return "long";
            if (type == typeof(decimal) || type == typeof(decimal?)) return "decimal";
            if (type == typeof(double) || type == typeof(double?)) return "double";
            if (type == typeof(float) || type == typeof(float?)) return "float";
            if (type == typeof(bool) || type == typeof(bool?)) return "bool";
            if (type == typeof(DateTime) || type == typeof(DateTime?)) return "datetime";
            if (type == typeof(Guid) || type == typeof(Guid?)) return "guid";

            return "json";
        }

        private string GetDefaultCategoryFromType(Type type)
        {
            if (type == typeof(bool) || type == typeof(bool?)) return "开关配置";
            if (type.IsPrimitive || type == typeof(decimal) || type == typeof(decimal?)) return "数值配置";
            if (type == typeof(DateTime) || type == typeof(DateTime?)) return "时间配置";
            if (type == typeof(string)) return "字符串配置";

            return "对象配置";
        }

        #endregion
    }
}